import os
import wx
import model
import dialog
import miyuki
import thread
import widget
import component

import resource as r

class Miyuki(widget.Presenter):
    """Miyuki presenter"""
    
    def __init__(self, view, interactor):
        super(Miyuki, self).__init__(view, interactor)
        config = miyuki.Config()
        self.restoreSize(config)
        self.restorePosition(config)
        self.restoreMaximized(config)
        self.restoreSashPosition(config)
        self.restoreSplitOrientation(config)
        self.restoreSplitView(config)
        self.db = wx.GetApp().openDb()
        self.view.ToolBar.filter.SetFocus()
    
    def close(self):
        config = miyuki.Config()
        self.saveMaximized(config)
        self.savePosition(config)
        self.saveSize(config)
        self.saveSashPosition(config)
        self.saveSplitOrientation(config)
        self.saveSplitView(config)
        self.view.Destroy()
    
    _about = None
    
    def showAbout(self):
        if not self._about: self._about = dialog.About(self.view)
        self._about.Center()
        self._about.Show()
    
    def restoreSashPosition(self, config):
        pos = config.ReadInt('%s/Sash' % self.view.Name, -1)
        if pos != -1: self.view.splitter.SashPosition = pos
        
        pos = config.ReadInt('%s/LeftSash' % self.view.Name, -1)
        if pos != -1: self.view.leftSplitter.SashPosition = pos
    
    def restoreSplitOrientation(self, config):
        mode = config.ReadInt('%s/SplitOrientation' % self.view.Name,
                              wx.SPLIT_VERTICAL)
        self.view.orientSplit(mode)
        
    def restoreSplitView(self, config):
        splitted = config.ReadInt('%s/Split' % self.view.Name, 0)
        self.view.showSplitter() if splitted else self.view.hideSplitter()
    
    def saveSplitOrientation(self, config):
        key = '%s/SplitOrientation' % self.view.Name
        config.WriteInt(key, self.view.splitter.SplitMode)
    
    def saveSplitView(self, config):
        key = '%s/Split' % self.view.Name
        config.WriteInt(key, 1 if self.view.splitter.IsSplit() else 0)
    
    def saveSashPosition(self, config):
        if self.view.splitter.IsSplit():
            key = '%s/Sash' % self.view.Name
            config.WriteInt(key, self.view.splitter.SashPosition)
            
        key = '%s/LeftSash' % self.view.Name
        config.WriteInt(key, self.view.leftSplitter.SashPosition)
    
    def toggleSplit(self):
        config = miyuki.Config()
        if self.view.splitter.IsSplit():
            self.saveSashPosition(config)
            self.view.hideSplitter()
        else:
            self.view.showSplitter()
            self.restoreSashPosition(config)
            
    def filter(self, tag):
        self.view.busyCursor()
        filters = []
        Post = model.Post
        not_ = model.sa.not_
        and_ = model.sa.and_
        
        self.view.models = []
        
        for tag in tag.split(' '):
            if tag[0] == '-':
                filters.append(not_(Post.tag.like('%' + tag[1:] + '%')))
            else:
                filters.append(Post.tag.like('%' + tag + '%'))
        posts = self.db.query(Post).filter(and_(*tuple(filters)))
        self.view.models = posts.order_by(Post.createdAt.desc())
        
        self.view.showSplitter()
        self.view.idle()
        
    def unfilter(self):
        self.view.models = []
        self.view.model = None
        self.view.ToolBar.filter.Value = ''
        self.enablePostsMenu()
        
    def show(self):
        """Show image for the corresponding post"""
        
        self.view.busyCursor()
        post = self.view.posts.selectedModel
        self.enablePostsMenu()
        self.view.model = post
        self.view.idle()
    
    def delete(self):
        """Set post status to deleted and delete the image file"""
        
        for post in self.view.posts.selectedModels:
            try: post.trash()
            except: pass
        if self.db.dirty: self.db.commit()
        
        self.view.posts.delete()
        self.view.image.model = None
    
    def enablePostsMenu(self):
        """Enable posts context menu"""
        
        state = True if self.view.posts.SelectedItemCount else False
        
        post = self.view.MenuBar.image.post
        post.save.Enable(state)
        post.delete.Enable(state)
        post.queue.Enable(state)
        post.download.Enable(state)
        
        toolBar = self.view.ToolBar
        toolBar.save.enable(state)
        toolBar.delete.enable(state)
        toolBar.queue.enable(state)
        toolBar.download.enable(state)
        
        menu = self.view.posts.menu
        menu.save.Enable(state)
        menu.delete.Enable(state)
        menu.queue.Enable(state)
        menu.download.Enable(state)
        
        state = True if self.view.posts.ItemCount else False
        
        post.export.Enable(state)
        toolBar.export.enable(state)
        menu.export.Enable(state)
    
    def queue(self):
        """Set post status to queued"""
        
        for post in self.view.posts.selectedModels:
            post.queue()
        if self.db.dirty: self.db.commit()
        
        self.view.posts.queue()
        
    def download(self):
        """Set post status to downloaded"""
        
        for post in self.view.posts.selectedModels:
            post.download()
        if self.db.dirty: self.db.commit()
        
        self.view.posts.download()
    
    def save(self):
        """Save selected post image"""
        
        path = self.view.dirDialog()
        if not path: return
        
        self.extract(self.view.posts.selectedModels, path)
        
    def export(self):
        """Export all filtered post image"""
        
        path = self.view.dirDialog()
        if not path: return
        
        self.view.busyCursor()
        thread.start_new_thread(self.extract, (self.view.models.all(), path))
        
    def extract(self, models, path):
        """Extract post image to another location.
        
        Args:
            models: A list of post model.
            path: A string of valid target directory.
        """
        
        exporting = 'Exporting image {:,} of {:,}...'
        
        total = len(models)
        wx.CallAfter(self.view.progressDialog, 'Export', 'Exporting images...',
                     total)
        
        for index, post in enumerate(models):
            t = (index, exporting)
            wx.CallAfter(self.view.updateProgress, index,
                         exporting.format(index + 1, total))
            retry = True
            try:
                post.export(path)
                retry = False
            except: pass
            
            if retry:
                try: post.export(path, True)
                except: continue
                
        wx.CallAfter(self.view.idle)
        
    def invite(self):
        """Add image to collection"""
        
        path = self.view.dirDialog()
        if not path: return
        
        imageDir = os.path.abspath('image')
        if path == imageDir:
            message = ('You cannot import from current collection.\n'
                       'Please select another directory.')
            style = style=wx.OK | wx.ICON_EXCLAMATION
            self.view.messageDialog(message, 'Error', style)
            return
        
        self.view.StatusBar.gauge.create()
        thread.start_new_thread(self.add, (path,))
        
    def add(self, path):
        """Hash image, move to collection and show it"""
        
        status = self.view.StatusBar
        wx.CallAfter(status.gauge.all.Show)
        dir = component.Directory(path)
        for file in dir.files:
            if file.isImage:
                file.reportHook = self.updateEachGauge
                print file.md5
##                status.StatusText = str(file)

##        wx.CallAfter(status.gauge.destroy, ())

    def updateEachGauge(self, total, progress):
        wx.CallAfter(self.view.StatusBar.gauge.each.update, total, progress)